package com.king.service;

import com.google.gson.JsonObject;
import com.king.config.GlobalConst;
import com.king.utils.CommonUtils;

/**
 * 微信客服功能
 * 当用户和公众号产生特定动作的交互时，微信将会把消息数据推送给开发者，
 * 开发者可以在一段时间内（目前修改为48小时）调用客服接口，
 * 通过POST一个JSON数据包来发送消息给普通用户。
 * 此接口主要用于客服等有人工消息处理环节的功能，方便开发者为用户提供更加优质的服务。
 *
 * 目前允许的动作列表如下（公众平台会根据运营情况更新该列表，不同动作触发后，允许的客服接口下发消息条数不同，下发条数达到上限后，会遇到错误返回码，具体请见返回码说明页）：
 * 1、用户发送信息
 * 2、点击自定义菜单（仅有点击推事件、扫码推事件、扫码推事件且弹出“消息接收中”提示框这3种菜单类型是会触发客服接口的）
 * 3、关注公众号
 * 4、扫描二维码
 * 5、支付成功
 *
 * 接口的统一参数说明
 * 参数	是否必须	说明
 * access_token	是	调用接口凭证
 * kf_account	是	完整客服账号，格式为：账号前缀@公众号微信号
 * kf_nick	是	客服昵称
 * kf_id	是	客服工号
 * nickname	是	客服昵称，最长6个汉字或12个英文字符
 * password	否	客服账号登录密码，格式为密码明文的32位加密MD5值。该密码仅用于在公众平台官网的多客服功能中使用，若不使用多客服功能，则不必设置密码
 * media	是	该参数仅在设置客服头像时出现，是form-data中媒体文件标识，有filename、filelength、content-type等信息
 */
public class WxKFService {

    private static final String CREATE_KF_URL = GlobalConst.getConfig("MP_CREATE_KF");
    private static final String UPDATE_KF_URL = GlobalConst.getConfig("MP_UPDATE_KF");
    private static final String DELETE_KF_URL = GlobalConst.getConfig("MP_DELETE_KF");
    private static final String SEND_MSG_KF_URL = GlobalConst.getConfig("MP_SEND_MSG_KF");
    private static final String TYPING_KF_URL = GlobalConst.getConfig("MP_TYPING_KF");

    //region 客服账号管理
    /**
     * 添加客服帐号
     * 开发者可以通过本接口为公众号添加客服账号，每个公众号最多添加10个客服账号。
     * 该接口调用请求如下：
     * http请求方式: POST
     * https://api.weixin.qq.com/customservice/kfaccount/add?access_token=ACCESS_TOKEN
     * POST数据格式：
     * {
     *      "kf_account" : "test1@test",
     *      "nickname" : "客服1",
     *      "password" : "pswmd5"
     * }
     * 返回说明（正确时的JSON返回结果）：
     * {
     *      "errcode" : 0,
     *      "errmsg" : "ok"
     * }
     */
    public boolean addKF(String data){
        String url =CREATE_KF_URL.replace("ACCESS_TOKEN",WxTokenService.getAccessToken());
        String result = CommonUtils.post(url, data);
        JsonObject jsonObject = GlobalConst.gson.fromJson(result, JsonObject.class);
        String errcode = jsonObject.get("errcode").getAsString();

        System.out.println("add kf url: "+url);
        System.out.println("add kf data: "+data);
        System.out.println("add kf result: "+result);

        return "0".equals(errcode);
    }

    /**
     * 修改客服帐号
     * 开发者可以通过本接口为公众号修改客服账号。该接口调用请求如下：
     * http请求方式: POST
     * https://api.weixin.qq.com/customservice/kfaccount/update?access_token=ACCESS_TOKEN
     * POST数据示例如下：
     * {
     *      "kf_account" : "test1@test",
     *      "nickname" : "客服1",
     *      "password" : "pswmd5"
     * }
     * 返回说明（正确时的JSON返回结果）：
     * {
     *      "errcode" : 0,
     *      "errmsg" : "ok"
     * }
     * @return
     */
    public boolean updateKF(String data){
        String url = UPDATE_KF_URL.replace("ACCESS_TOKEN",WxTokenService.getAccessToken());
        String result = CommonUtils.post(url, data);
        JsonObject jsonObject = GlobalConst.gson.fromJson(result, JsonObject.class);
        String errcode = jsonObject.get("errcode").getAsString();
        return "0".equals(errcode);
    }

    /**
     * 删除客服帐号
     * 开发者可以通过该接口为公众号删除客服帐号。该接口调用请求如下：
     * http请求方式: POST
     * https://api.weixin.qq.com/customservice/kfaccount/del?access_token=ACCESS_TOKEN
     * POST数据示例如下：
     * {
     *      "kf_account" : "test1@test",
     *      "nickname" : "客服1",
     *      "password" : "pswmd5"
     * }
     * 返回说明（正确时的JSON返回结果）：
     * {
     *      "errcode" : 0,
     *      "errmsg" : "ok"
     * }
     * @param data
     * @return
     */
    public boolean deleteKF(String data){
        String url = DELETE_KF_URL.replace("ACCESS_TOKEN",WxTokenService.getAccessToken());
        String result = CommonUtils.post(url, data);
        JsonObject jsonObject = GlobalConst.gson.fromJson(result, JsonObject.class);
        String errcode = jsonObject.get("errcode").getAsString();
        return "0".equals(errcode);
    }
    //endregion

    /**
     * 客服接口-发消息
     * http请求方式: POST
     * https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
     *
     * 1、发送文本消息
     * {
     *     "touser":"OPENID",
     *     "msgtype":"text",
     *     "text":
     *     {
     *          "content":"Hello World"
     *     }
     * }
     * 如果需要以某个客服帐号来发消息（在微信6.0.2及以上版本中显示自定义头像），
     * 则需在JSON数据包的后半部分加入customservice参数，例如发送文本消息则改为：
     * {
     *     "touser":"OPENID",
     *     "msgtype":"text",
     *     "text":
     *     {
     *          "content":"Hello World"
     *     },
     *     "customservice":
     *     {
     *          "kf_account": "test1@kftest"
     *     }
     * }
     *
     * 2、发送图片消息
     * {
     *     "touser":"OPENID",
     *     "msgtype":"image",
     *     "image":
     *     {
     *       "media_id":"MEDIA_ID"
     *     }
     * }
     *
     * 3、发送语音消息
     * {
     *     "touser":"OPENID",
     *     "msgtype":"voice",
     *     "voice":
     *     {
     *       "media_id":"MEDIA_ID"
     *     }
     * }
     *
     * 4、发送视频消息
     * {
     *     "touser":"OPENID",
     *     "msgtype":"video",
     *     "video":
     *     {
     *       "media_id":"MEDIA_ID",
     *       "thumb_media_id":"MEDIA_ID",
     *       "title":"TITLE",
     *       "description":"DESCRIPTION"
     *     }
     * }
     *
     * 5、发送音乐消息
     * {
     *     "touser":"OPENID",
     *     "msgtype":"music",
     *     "music":
     *     {
     *       "title":"MUSIC_TITLE",
     *       "description":"MUSIC_DESCRIPTION",
     *       "musicurl":"MUSIC_URL",
     *       "hqmusicurl":"HQ_MUSIC_URL",
     *       "thumb_media_id":"THUMB_MEDIA_ID"
     *     }
     * }
     *
     * 6.1、发送图文消息（点击跳转到外链） 图文消息条数限制在1条以内，注意，如果图文数超过1，则将会返回错误码45008。
     * {
     *     "touser":"OPENID",
     *     "msgtype":"news",
     *     "news":{
     *         "articles": [
     *          {
     *              "title":"Happy Day",
     *              "description":"Is Really A Happy Day",
     *              "url":"URL",
     *              "picurl":"PIC_URL"
     *          }
     *          ]
     *     }
     * }
     *
     * 6.2、发送图文消息（点击跳转到图文消息页面） 图文消息条数限制在1条以内，注意，如果图文数超过1，则将会返回错误码45008。
     * {
     *     "touser":"OPENID",
     *     "msgtype":"mpnews",
     *     "mpnews":
     *     {
     *          "media_id":"MEDIA_ID"
     *     }
     * }
     *
     * 7、发送菜单消息
     * {
     *   "touser": "OPENID"
     *   "msgtype": "msgmenu",
     *   "msgmenu": {
     *     "head_content": "您对本次服务是否满意呢? "
     *     "list": [
     *       {
     *         "id": "101",
     *         "content": "满意"
     *       },
     *       {
     *         "id": "102",
     *         "content": "不满意"
     *       }
     *     ],
     *     "tail_content": "欢迎再次光临"
     *   }
     * }
     * 其中，“满意”和“不满意”是可点击的，当用户点击后，微信会发送一条XML消息到开发者服务器，格式如下：
     * <xml>
     *  <ToUserName><![CDATA[ToUser]]></ToUserName>
     *  <FromUserName><![CDATA[FromUser]]></FromUserName>
     *  <CreateTime>1500000000</CreateTime>
     *  <MsgType><![CDATA[text]]></MsgType>
     *  <Content><![CDATA[满意]]></Content>
     *  <MsgId>1234567890123456</MsgId>
     *  <bizmsgmenuid>101</bizmsgmenuid>
     * </xml>
     * 参数	说明
     * ToUserName	开发者帐号
     * FromUserName	接收方帐号（OpenID）
     * CreateTime	消息创建时间戳
     * MsgType	Text
     * Content	点击的菜单名
     * MsgId	消息ID
     * bizmsgmenuid	点击的菜单ID
     * 收到XML推送之后，开发者可以根据提取出来的bizmsgmenuid和Content识别出微信用户点击的是哪个菜单。
     *
     * 8、发送卡券
     * {
     *   "touser":"OPENID",
     *   "msgtype":"wxcard",
     *   "wxcard":
     *   {
     *    "card_id":"123dsdajkasd231jhksad"
     *    }
     * }
     * 特别注意客服消息接口投放卡券仅支持非自定义Code码和导入code模式的卡券的卡券
     *
     * 9、发送小程序卡片（要求小程序与公众号已关联）
     * {
     *     "touser":"OPENID",
     *     "msgtype":"miniprogrampage",
     *     "miniprogrampage":
     *     {
     *         "title":"title",
     *         "appid":"appid",
     *         "pagepath":"pagepath",
     *         "thumb_media_id":"thumb_media_id"
     *     }
     * }
     *
     * 接口的统一参数说明
     * 参数	是否必须	说明
     * access_token	是	调用接口凭证
     * touser	是	普通用户openid
     * msgtype	是	消息类型，文本为text，图片为image，语音为voice，视频消息为video，音乐消息为music，图文消息（点击跳转到外链）为news，图文消息（点击跳转到图文消息页面）为mpnews，卡券为wxcard，小程序为miniprogrampage
     * content	是	文本消息内容
     * media_id	是	发送的图片/语音/视频/图文消息（点击跳转到图文消息页）的媒体ID
     * thumb_media_id	是	缩略图/小程序卡片图片的媒体ID，小程序卡片图片建议大小为520*416
     * title	否	图文消息/视频消息/音乐消息/小程序卡片的标题
     * description	否	图文消息/视频消息/音乐消息的描述
     * musicurl	是	音乐链接
     * hqmusicurl	是	高品质音乐链接，wifi环境优先使用该链接播放音乐
     * url	否	图文消息被点击后跳转的链接
     * picurl	否	图文消息的图片链接，支持JPG、PNG格式，较好的效果为大图640*320，小图80*80
     * appid	是	小程序的appid，要求小程序的appid需要与公众号有关联关系
     * pagepath	是	小程序的页面路径，跟app.json对齐，支持参数，比如pages/index/index?foo=bar
     */
    public boolean sendKFMessage(String data){
        String url = SEND_MSG_KF_URL.replace("ACCESS_TOKEN",WxTokenService.getAccessToken());
        String result = CommonUtils.post(url, data);
        JsonObject jsonObject = GlobalConst.gson.fromJson(result, JsonObject.class);
        String errcode = jsonObject.get("errcode").getAsString();

        System.out.println(url);
        System.out.println(data);
        System.out.println(result);

        return "0".equals(errcode);
    }

    /**
     * 客服输入状态
     * 开发者可通过调用“客服输入状态”接口，返回客服当前输入状态给用户。
     * 此接口需要客服消息接口权限。
     * 1、如果不满足发送客服消息的触发条件，则无法下发输入状态。
     * 2、下发输入状态，需要客服之前30秒内跟用户有过消息交互。
     * 3、在输入状态中（持续15s），不可重复下发输入态。
     * 4、在输入状态中，如果向用户下发消息，会同时取消输入状态。
     *
     * http请求方式: POST
     * https://api.weixin.qq.com/cgi-bin/message/custom/typing?access_token=ACCESS_TOKEN
     * JSON数据包如下：
     *  { "touser":"OPENID", "command":"Typing"}
     *  参数	是否必须	说明
     * access_token	是	调用接口凭证
     * touser	是	普通用户（openid）
     * command	是	"Typing"：对用户下发“正在输入"状态 "CancelTyping"：取消对用户的”正在输入"状态
     *
     * 预期返回：
     *  { "errcode":0, "errmsg":"ok"}
     *  参数	说明
     * 45072	command字段取值不对
     * 45080	下发输入状态，需要之前30秒内跟用户有过消息交互
     * 45081	已经在输入状态，不可重复下发
     *
     * @return
     */
    public boolean getKFTyping(String data){
        String url = TYPING_KF_URL.replace("ACCESS_TOKEN",WxTokenService.getAccessToken());
        String result = CommonUtils.post(url, data);
        JsonObject jsonObject = GlobalConst.gson.fromJson(result, JsonObject.class);
        String errcode = jsonObject.get("errcode").getAsString();
        return "0".equals(errcode);
    }
}
